package main

import "fmt"
import "jvmgo/ch05/classfile"
import "jvmgo/ch05/instructions"
import "jvmgo/ch05/instructions/base"
import "jvmgo/ch05/rtda"

func interpret(methodInfo *classfile.MemberInfo) {
	codeAttr := methodInfo.CodeAttribute()
	maxLocals := codeAttr.MaxLocals()
	maxStack := codeAttr.MaxStack()
	bytecode := codeAttr.Code()

	thread := rtda.NewThread()
	frame := thread.NewFrame(maxLocals, maxStack)
	thread.PushFrame(frame)

	defer catchErr(frame)
	loop(thread, bytecode)
}

func catchErr(frame *rtda.Frame) {
	if r := recover(); r != nil {
		printInfo(frame)
		panic(r)
	}
}

func printInfo(frame *rtda.Frame) {
	fmt.Printf("LocalVars:%v\n", frame.LocalVars())
	fmt.Printf("OperandStack:%v\n", frame.OperandStack())
	fmt.Println(frame.OperandStack().Size())
}
func loop(thread *rtda.Thread, bytecode []byte) {
	frame := thread.PopFrame()
	reader := &base.BytecodeReader{} //实例化BytecodeReader类型
	fmt.Print("----bytecode len:-----")
	fmt.Println(len(bytecode))
	for {
		pc := frame.NextPC() //第一次执行时，刚刚初始化Frame对象，所以nextpc的值为0
		//thread.SetPC(pc) //在ch05，这里可以注释掉，暂时没用到。
		if pc >= len(bytecode){
			printInfo(frame)
			return
		}
		// decode
		reader.Reset(bytecode, pc)
		opcode := reader.ReadUint8() //读取操作码的时候pc的值一定会加一，因为操作码只占一个字节。
		inst := instructions.NewInstruction(opcode)
		inst.FetchOperands(reader) //这里也可能导致pc值增加，因为有些执行提取操作数时会读取代码数据，如果不读，那么pc值不增加。

		frame.SetNextPC(reader.PC())

		// execute
		fmt.Printf("-----pc:%2d inst:%T %v\n", pc, inst, inst)
		inst.Execute(frame)
	}
}
